package com.zyx.order.server.service.impl;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.rabbitmq.client.*;
import com.zyx.order.server.common.enums.OrderStatus;
import com.zyx.order.server.mapper.OrderDetailMapper;
import com.zyx.order.server.model.dto.OrderMessageDTO;
import com.zyx.order.server.model.po.OrderDetailPO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.ExchangeTypes;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

@Slf4j
@Service
public class OrderMessageService {

    @Autowired
    private OrderDetailMapper orderDetailMapper;

    @Autowired
    private ObjectMapper objectMapper;

    /* ==================== Step1:原生方法实现 Exchange、Queue、Binding 的声明以及消息的消费 ==================== */
    // @Async
    // public void handleMessage() throws IOException, TimeoutException, InterruptedException {
    //     log.info("start linstening message");
    //     ConnectionFactory connectionFactory = new ConnectionFactory();
    //     connectionFactory.setHost("81.68.117.201");
    //     try (Connection connection = connectionFactory.newConnection();
    //          Channel channel = connection.createChannel()) {
    //
    //         /*---------------------restaurant---------------------*/
    //         channel.exchangeDeclare("exchange.order.restaurant", BuiltinExchangeType.DIRECT, true, false, null);
    //         channel.queueDeclare("queue.order", true, false, false, null);
    //         channel.queueBind("queue.order", "exchange.order.restaurant", "key.order");
    //
    //         /*---------------------deliveryman---------------------*/
    //         channel.exchangeDeclare("exchange.order.deliveryman", BuiltinExchangeType.DIRECT, true, false, null);
    //         channel.queueBind("queue.order", "exchange.order.deliveryman", "key.order");
    //
    //         /*---------------------settlement---------------------*/
    //         channel.exchangeDeclare("exchange.settlement.order", BuiltinExchangeType.FANOUT, true, false, null);
    //         channel.queueBind("queue.order", "exchange.settlement.order", "key.order");
    //
    //         /*---------------------reward---------------------*/
    //         channel.exchangeDeclare("exchange.order.reward", BuiltinExchangeType.TOPIC, true, false, null);
    //         channel.queueBind("queue.order", "exchange.order.reward", "key.order");
    //         channel.basicConsume("queue.order", true, deliverCallback, consumerTag -> {});
    //
    //         while (true) {
    //             Thread.sleep(1000);
    //         }
    //     }
    // }


    /* ==================== Step2:原生方法处理消息的消费， Config中的Bean处理 Exchange、Queue、Binding 的声明 ==================== */
    // @Async
    // public void handleMessage() throws IOException, TimeoutException, InterruptedException {
    //     TimeUnit.SECONDS.sleep(5);
    //     log.info("start linstening message");
    //     ConnectionFactory connectionFactory = new ConnectionFactory();
    //     connectionFactory.setHost("81.68.117.201");
    //     try (Connection connection = connectionFactory.newConnection();
    //          Channel channel = connection.createChannel()) {
    //         channel.basicConsume("queue.order", true, deliverCallback, consumerTag -> {});
    //         while (true) {
    //             Thread.sleep(1000);
    //         }
    //     }
    // }
    //
    // DeliverCallback deliverCallback = (consumerTag, message) -> {
    //     String messageBody = new String(message.getBody());
    //     log.info("deliverCallback:messageBody:{}", messageBody);
    //     ConnectionFactory connectionFactory = new ConnectionFactory();
    //     connectionFactory.setHost("81.68.117.201");
    //     try {
    //         OrderMessageDTO orderMessageDTO = objectMapper.readValue(messageBody, OrderMessageDTO.class);
    //         OrderDetailPO orderPO = orderDetailMapper.selectById(orderMessageDTO.getOrderId());
    //         switch (orderPO.getStatus()) {
    //             case ORDER_CREATING:
    //                 if (orderMessageDTO.getConfirmed() && null != orderMessageDTO.getPrice()) {
    //                     orderPO.setStatus(OrderStatus.RESTAURANT_CONFIRMED);
    //                     orderPO.setPrice(orderMessageDTO.getPrice());
    //                     orderDetailMapper.updateById(orderPO);
    //                     try (Connection connection = connectionFactory.newConnection();
    //                          Channel channel = connection.createChannel()) {
    //                         String messageToSend = objectMapper.writeValueAsString(orderMessageDTO);
    //                         channel.basicPublish("exchange.order.deliveryman", "key.deliveryman", null,
    //                                 messageToSend.getBytes());
    //                     }
    //                 } else {
    //                     orderPO.setStatus(OrderStatus.FAILED);
    //                     orderDetailMapper.updateById(orderPO);
    //                 }
    //                 break;
    //             case RESTAURANT_CONFIRMED:
    //                 if (null != orderMessageDTO.getDeliverymanId()) {
    //                     orderPO.setStatus(OrderStatus.DELIVERYMAN_CONFIRMED);
    //                     orderPO.setDeliverymanId(orderMessageDTO.getDeliverymanId());
    //                     orderDetailMapper.updateById(orderPO);
    //                     try (Connection connection = connectionFactory.newConnection();
    //                          Channel channel = connection.createChannel()) {
    //                         String messageToSend = objectMapper.writeValueAsString(orderMessageDTO);
    //                         channel.basicPublish("exchange.order.settlement", "key.settlement", null,
    //                                 messageToSend.getBytes());
    //                     }
    //                 } else {
    //                     orderPO.setStatus(OrderStatus.FAILED);
    //                     orderDetailMapper.updateById(orderPO);
    //                 }
    //                 break;
    //             case DELIVERYMAN_CONFIRMED:
    //                 if (null != orderMessageDTO.getSettlementId()) {
    //                     orderPO.setStatus(OrderStatus.SETTLEMENT_CONFIRMED);
    //                     orderPO.setSettlementId(orderMessageDTO.getSettlementId());
    //                     orderDetailMapper.updateById(orderPO);
    //                     try (Connection connection = connectionFactory.newConnection();
    //                          Channel channel = connection.createChannel()) {
    //                         String messageToSend = objectMapper.writeValueAsString(orderMessageDTO);
    //                         channel.basicPublish("exchange.order.reward", "key.reward", null, messageToSend.getBytes());
    //                     }
    //                 } else {
    //                     orderPO.setStatus(OrderStatus.FAILED);
    //                     orderDetailMapper.updateById(orderPO);
    //                 }
    //                 break;
    //             case SETTLEMENT_CONFIRMED:
    //                 if (null != orderMessageDTO.getRewardId()) {
    //                     orderPO.setStatus(OrderStatus.ORDER_CREATED);
    //                     orderPO.setRewardId(orderMessageDTO.getRewardId());
    //                     orderDetailMapper.updateById(orderPO);
    //                 } else {
    //                     orderPO.setStatus(OrderStatus.FAILED);
    //                     orderDetailMapper.updateById(orderPO);
    //                 }
    //                 break;
    //         }
    //     } catch (JsonProcessingException | TimeoutException e) {
    //         e.printStackTrace();
    //     }
    // };

    /*==================================== 不使用MessageConverter ====================================*/
    // public void handleMessage(byte[] messageBody) throws IOException {
    //     log.info("handleMessage:messageBody:{}", new String(messageBody));
    //     ConnectionFactory connectionFactory = new ConnectionFactory();
    //     connectionFactory.setHost("81.68.117.201");
    //     try {
    //         OrderMessageDTO orderMessageDTO = objectMapper.readValue(new String(messageBody), OrderMessageDTO.class);
    //         OrderDetailPO orderPO = orderDetailMapper.selectById(orderMessageDTO.getOrderId());
    //         switch (orderPO.getStatus()) {
    //             case ORDER_CREATING:
    //                 if (orderMessageDTO.getConfirmed() && null != orderMessageDTO.getPrice()) {
    //                     orderPO.setStatus(OrderStatus.RESTAURANT_CONFIRMED);
    //                     orderPO.setPrice(orderMessageDTO.getPrice());
    //                     orderDetailMapper.updateById(orderPO);
    //                     try (Connection connection = connectionFactory.newConnection();
    //                          Channel channel = connection.createChannel()) {
    //                         String messageToSend = objectMapper.writeValueAsString(orderMessageDTO);
    //                         channel.basicPublish("exchange.order.deliveryman", "key.deliveryman", null,
    //                                 messageToSend.getBytes());
    //                     }
    //                 } else {
    //                     orderPO.setStatus(OrderStatus.FAILED);
    //                     orderDetailMapper.updateById(orderPO);
    //                 }
    //                 break;
    //             case RESTAURANT_CONFIRMED:
    //                 if (null != orderMessageDTO.getDeliverymanId()) {
    //                     orderPO.setStatus(OrderStatus.DELIVERYMAN_CONFIRMED);
    //                     orderPO.setDeliverymanId(orderMessageDTO.getDeliverymanId());
    //                     orderDetailMapper.updateById(orderPO);
    //                     try (Connection connection = connectionFactory.newConnection();
    //                          Channel channel = connection.createChannel()) {
    //                         String messageToSend = objectMapper.writeValueAsString(orderMessageDTO);
    //                         channel.basicPublish("exchange.order.settlement", "key.settlement", null,
    //                                 messageToSend.getBytes());
    //                     }
    //                 } else {
    //                     orderPO.setStatus(OrderStatus.FAILED);
    //                     orderDetailMapper.updateById(orderPO);
    //                 }
    //                 break;
    //             case DELIVERYMAN_CONFIRMED:
    //                 if (null != orderMessageDTO.getSettlementId()) {
    //                     orderPO.setStatus(OrderStatus.SETTLEMENT_CONFIRMED);
    //                     orderPO.setSettlementId(orderMessageDTO.getSettlementId());
    //                     orderDetailMapper.updateById(orderPO);
    //                     try (Connection connection = connectionFactory.newConnection();
    //                          Channel channel = connection.createChannel()) {
    //                         String messageToSend = objectMapper.writeValueAsString(orderMessageDTO);
    //                         channel.basicPublish("exchange.order.reward", "key.reward", null, messageToSend.getBytes());
    //                     }
    //                 } else {
    //                     orderPO.setStatus(OrderStatus.FAILED);
    //                     orderDetailMapper.updateById(orderPO);
    //                 }
    //                 break;
    //             case SETTLEMENT_CONFIRMED:
    //                 if (null != orderMessageDTO.getRewardId()) {
    //                     orderPO.setStatus(OrderStatus.ORDER_CREATED);
    //                     orderPO.setRewardId(orderMessageDTO.getRewardId());
    //                     orderDetailMapper.updateById(orderPO);
    //                 } else {
    //                     orderPO.setStatus(OrderStatus.FAILED);
    //                     orderDetailMapper.updateById(orderPO);
    //                 }
    //                 break;
    //         }
    //     } catch (JsonProcessingException | TimeoutException e) {
    //         e.printStackTrace();
    //     }
    // }


    /*==================================== 使用MessageConverter ====================================*/
    // public void handleMessage(OrderMessageDTO orderMessageDTO) throws IOException {
    //     log.info("handleMessage:messageBody:{}", orderMessageDTO);
    //     ConnectionFactory connectionFactory = new ConnectionFactory();
    //     connectionFactory.setHost("81.68.117.201");
    //     try {
    //         OrderDetailPO orderPO = orderDetailMapper.selectById(orderMessageDTO.getOrderId());
    //         switch (orderPO.getStatus()) {
    //             case ORDER_CREATING:
    //                 if (orderMessageDTO.getConfirmed() && null != orderMessageDTO.getPrice()) {
    //                     orderPO.setStatus(OrderStatus.RESTAURANT_CONFIRMED);
    //                     orderPO.setPrice(orderMessageDTO.getPrice());
    //                     orderDetailMapper.updateById(orderPO);
    //                     try (Connection connection = connectionFactory.newConnection();
    //                          Channel channel = connection.createChannel()) {
    //                         String messageToSend = objectMapper.writeValueAsString(orderMessageDTO);
    //                         channel.basicPublish("exchange.order.deliveryman", "key.deliveryman", null,
    //                                 messageToSend.getBytes());
    //                     }
    //                 } else {
    //                     orderPO.setStatus(OrderStatus.FAILED);
    //                     orderDetailMapper.updateById(orderPO);
    //                 }
    //                 break;
    //             case RESTAURANT_CONFIRMED:
    //                 if (null != orderMessageDTO.getDeliverymanId()) {
    //                     orderPO.setStatus(OrderStatus.DELIVERYMAN_CONFIRMED);
    //                     orderPO.setDeliverymanId(orderMessageDTO.getDeliverymanId());
    //                     orderDetailMapper.updateById(orderPO);
    //                     try (Connection connection = connectionFactory.newConnection();
    //                          Channel channel = connection.createChannel()) {
    //                         String messageToSend = objectMapper.writeValueAsString(orderMessageDTO);
    //                         channel.basicPublish("exchange.order.settlement", "key.settlement", null,
    //                                 messageToSend.getBytes());
    //                     }
    //                 } else {
    //                     orderPO.setStatus(OrderStatus.FAILED);
    //                     orderDetailMapper.updateById(orderPO);
    //                 }
    //                 break;
    //             case DELIVERYMAN_CONFIRMED:
    //                 if (null != orderMessageDTO.getSettlementId()) {
    //                     orderPO.setStatus(OrderStatus.SETTLEMENT_CONFIRMED);
    //                     orderPO.setSettlementId(orderMessageDTO.getSettlementId());
    //                     orderDetailMapper.updateById(orderPO);
    //                     try (Connection connection = connectionFactory.newConnection();
    //                          Channel channel = connection.createChannel()) {
    //                         String messageToSend = objectMapper.writeValueAsString(orderMessageDTO);
    //                         channel.basicPublish("exchange.order.reward", "key.reward", null, messageToSend.getBytes());
    //                     }
    //                 } else {
    //                     orderPO.setStatus(OrderStatus.FAILED);
    //                     orderDetailMapper.updateById(orderPO);
    //                 }
    //                 break;
    //             case SETTLEMENT_CONFIRMED:
    //                 if (null != orderMessageDTO.getRewardId()) {
    //                     orderPO.setStatus(OrderStatus.ORDER_CREATED);
    //                     orderPO.setRewardId(orderMessageDTO.getRewardId());
    //                     orderDetailMapper.updateById(orderPO);
    //                 } else {
    //                     orderPO.setStatus(OrderStatus.FAILED);
    //                     orderDetailMapper.updateById(orderPO);
    //                 }
    //                 break;
    //         }
    //     } catch (JsonProcessingException | TimeoutException e) {
    //         e.printStackTrace();
    //     }
    // }


    @RabbitListener(
            // containerFactory = "rabbitListenerContainerFactory",
            // queues = "queue.order",
            // admin = "rabbitAdmin",
            bindings = {
                    @QueueBinding(
                            // value = @Queue(name = "${imooc.order-queue}",
                            value = @Queue(name = "queue.order"
                                    // ,arguments = {
                                    //         @Argument(name = "x-message-ttl", value = "1000", type = "java.lang.Integer"),
                                    //         @Argument(name = "x-dead-letter-exchange", value = "aaaaa"),
                                    //         @Argument(name = "x-dead-letter-routing-key", value = "bbbb")
                                    // }
                            ),
                            exchange = @Exchange(name = "exchange.order.restaurant", type = ExchangeTypes.DIRECT),
                            key = "key.order"
                    ),
                    @QueueBinding(
                            value = @Queue(name = "queue.order"),
                            exchange = @Exchange(name = "exchange.order.deliveryman", type = ExchangeTypes.DIRECT),
                            key = "key.order"
                    ),
                    @QueueBinding(
                            value = @Queue(name = "queue.order"),
                            exchange = @Exchange(name = "exchange.settlement.order", type = ExchangeTypes.FANOUT),
                            key = "key.order"
                    ),
                    @QueueBinding(
                            value = @Queue(name = "queue.order"),
                            exchange = @Exchange(name = "exchange.order.reward", type = ExchangeTypes.TOPIC),
                            key = "key.order"
                    )
            }
    )

    public void handleMessage(@Payload Message message) throws
            IOException {
        log.info("handleMessage:message:{}", new String(message.getBody()));
        ConnectionFactory connectionFactory = new ConnectionFactory();
        connectionFactory.setHost("localhost");
        try {
            OrderMessageDTO orderMessageDTO = objectMapper.readValue(message.getBody(),
                    OrderMessageDTO.class);
            OrderDetailPO orderPO = orderDetailMapper.selectById(orderMessageDTO.getOrderId());

            switch (orderPO.getStatus()) {

                case ORDER_CREATING:
                    if (orderMessageDTO.getConfirmed() && null != orderMessageDTO.getPrice()) {
                        orderPO.setStatus(OrderStatus.RESTAURANT_CONFIRMED);
                        orderPO.setPrice(orderMessageDTO.getPrice());
                        orderDetailMapper.updateById(orderPO);
                        try (Connection connection = connectionFactory.newConnection();
                             Channel channel = connection.createChannel()) {
                            String messageToSend = objectMapper.writeValueAsString(orderMessageDTO);
                            channel.basicPublish("exchange.order.deliveryman", "key.deliveryman", null,
                                    messageToSend.getBytes());
                        }
                    } else {
                        orderPO.setStatus(OrderStatus.FAILED);
                        orderDetailMapper.updateById(orderPO);
                    }
                    break;
                case RESTAURANT_CONFIRMED:
                    if (null != orderMessageDTO.getDeliverymanId()) {
                        orderPO.setStatus(OrderStatus.DELIVERYMAN_CONFIRMED);
                        orderPO.setDeliverymanId(orderMessageDTO.getDeliverymanId());
                        orderDetailMapper.updateById(orderPO);
                        try (Connection connection = connectionFactory.newConnection();
                             Channel channel = connection.createChannel()) {
                            String messageToSend = objectMapper.writeValueAsString(orderMessageDTO);
                            channel.basicPublish(
                                    "exchange.order.settlement",
                                    "key.settlement",
                                    null,
                                    messageToSend.getBytes()
                            );
                        }
                    } else {
                        orderPO.setStatus(OrderStatus.FAILED);
                        orderDetailMapper.updateById(orderPO);
                    }
                    break;
                case DELIVERYMAN_CONFIRMED:
                    if (null != orderMessageDTO.getSettlementId()) {
                        orderPO.setStatus(OrderStatus.SETTLEMENT_CONFIRMED);
                        orderPO.setSettlementId(orderMessageDTO.getSettlementId());
                        orderDetailMapper.updateById(orderPO);
                        try (Connection connection = connectionFactory.newConnection();
                             Channel channel = connection.createChannel()) {
                            String messageToSend = objectMapper.writeValueAsString(orderMessageDTO);
                            channel.basicPublish(
                                    "exchange.order.reward",
                                    "key.reward",
                                    null,
                                    messageToSend.getBytes()
                            );
                        }
                    } else {
                        orderPO.setStatus(OrderStatus.FAILED);
                        orderDetailMapper.updateById(orderPO);
                    }
                    break;
                case SETTLEMENT_CONFIRMED:
                    if (null != orderMessageDTO.getRewardId()) {
                        orderPO.setStatus(OrderStatus.ORDER_CREATED);
                        orderPO.setRewardId(orderMessageDTO.getRewardId());
                        orderDetailMapper.updateById(orderPO);
                    } else {
                        orderPO.setStatus(OrderStatus.FAILED);
                        orderDetailMapper.updateById(orderPO);
                    }
                    break;
            }
        } catch (JsonProcessingException | TimeoutException e) {
            e.printStackTrace();
        }
    }
}
